﻿namespace Numbrella.TaskSamples.PiMonteCarlo
{
    using System;
    using System.Globalization;
    using Numbrella.Core;
    
    public class Problem : ProblemImplementationBase<Task, ResultContents>
	{
		#region Fields

		private readonly ResultValidator resultValidator = new ResultValidator();

		private readonly object syncRoot = new object();
		
		private readonly long expoPerPortion;

		private decimal dropsSum;

	    private decimal dropsCount;

        private decimal resultingPi;
	    
		#endregion

        public Problem(long expoPerPortion, int taskCount, int taskEvaluationCount)
			: base("Pi number", "Calculate Pi using MonteCarlo method", taskCount, taskEvaluationCount)
		{
			if (expoPerPortion < 1)
				throw new ArgumentOutOfRangeException("expoPerPortion", "There is no point having zero random drops in this task.");
			if (taskCount < 1)
				throw new ArgumentOutOfRangeException("taskCount", "There is no point in having no tasks.");
            this.expoPerPortion = expoPerPortion;
		}

		public override IResultValidator<ResultContents> ResultValidator
		{
			get { return this.resultValidator; }
		}

		protected override Task CreateTaskForId(int id)
		{
			return new Task(this.expoPerPortion, id);
		}

		protected override void AccumulateResult(TaskResult<ResultContents> result)
		{
            lock (this.syncRoot)
            {
                this.dropsCount = result.Contents.DropsCount + this.dropsCount;
                this.dropsSum = result.Contents.DropsSum + this.dropsSum;
                this.resultingPi = ((this.dropsSum * 4.0m) / this.dropsCount);
            }
		}
            
		protected override void OnProblemSolved(EventArgs e)
		{
            System.Windows.MessageBox.Show(string.Format(CultureInfo.CurrentCulture, "Resulting Pi number is {0}", this.resultingPi), "Solution found!");
        }

		protected override TimeSpan GetTimeoutForTask(int taskId)
		{
			return TimeSpan.FromMinutes(1);
		}
	}
}
